package durak.server.servlets;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import com.google.gson.Gson;

import durak.common.model.Card;
import durak.common.model.DurakDeck;
import durak.common.model.Card.Rank;
import durak.common.model.Card.Suit;
import durak.server.control.Game;
import durak.server.control.GamesManager;
import durak.server.control.PlayerControl;
import durak.server.control.PlayerControlAutomatic;
import durak.server.model.Player;
import durak.server.model.Player.playerType;
import durak.utils.ServletUtils;

import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Servlet implementation class DurakXMLFileUploader
 */
@WebServlet(name = "upload", urlPatterns = { "/upload" })
public class DurakXMLFileUploader extends HttpServlet {
	private static final long serialVersionUID = 1L;

	Card card;
	Element eElement;
	ArrayList<Player> players;
	DurakDeck deck;
	String playerName;
	String suit;
	String rank;
	Player player;

	private int autoPlayers = 0;
	private int humanPlayers = 0;
	private String gameName;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public DurakXMLFileUploader() {
		super();
		// TODO Auto-generated constructor stub
	}

	private void handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Throwable {
		Gson gson = new Gson();

		try {
			List<FileItem> items = new ServletFileUpload(
					new DiskFileItemFactory()).parseRequest(request);
			for (FileItem item : items) {
				if (item.isFormField()) {
					// Process regular form field (input
					// type="text|radio|checkbox|etc", select, etc).
					String fieldname = item.getFieldName();
					String fieldvalue = item.getString();
				} else {
					// Process form file field (input type="file").
					String fieldname = item.getFieldName();
					InputStream filecontent = item.getInputStream();
					// parse
					parseXmlFile(filecontent);
					// create and publish new game
					Game game = new Game(gameName, humanPlayers, autoPlayers,true);
					System.out.println("New game name is: " + gameName
							+ " with " + humanPlayers + " human palyers and "
							+ autoPlayers + " auto players");
					initAutoPlayers(autoPlayers, game);
					initExpectedHumanPlayers(humanPlayers,game);
					game.getGamingTable().setDeck(returnDeck());
					GamesManager gameManager = ServletUtils.getGamesManager(getServletContext());
					gameManager.addGame(game);
					String jsonResponse = gson.toJson(gameManager.getGamesDescriptions());
					response.getWriter().print(jsonResponse);
					response.getWriter().flush();
				}
			}
		} catch (FileUploadException e) {
			throw new ServletException("Cannot parse multipart request.", e);
		}

	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		try {
			handleRequest(request, response);
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		try {
			handleRequest(request, response);
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void parseXmlFile(InputStream xmlFileStream) throws Throwable {
		humanPlayers =0; autoPlayers=0;
		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
				.newInstance();
		DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
		Document doc = docBuilder.parse(xmlFileStream);
		doc.getDocumentElement().normalize();

		players = new ArrayList<Player>();
		NodeList playersList = doc.getElementsByTagName("player"); // 2 players

		for (int i = 0; i < playersList.getLength(); i++) {
			Node fstNode = playersList.item(i);// player

			if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
				Element fstElmnt = (Element) fstNode;
				String type = fstElmnt.getAttribute("type");

				if (type.equals("HUMAN")) {
					playerName = fstElmnt.getAttribute("name");
					humanPlayers++;
					gameName = fstElmnt.getAttribute("name") + "'s Game";
					player = new Player();// creating a new human player
					player.setName(playerName);
					player.setType(Player.playerType.HUMAN);
					players.add(player);

				}

				else if (type.equals("COMPUTER")) {
					playerName = fstElmnt.getAttribute("name");
					autoPlayers++;
					player = new Player();// creating a new human player
					player.setName(playerName);
					player.setType(Player.playerType.COMPUTER);
					players.add(player);
				}

			}
		}

		deck = new DurakDeck();
		NodeList cardsList = doc.getElementsByTagName("card");

		for (int i = 0; i < cardsList.getLength(); i++) {
			Node fstNode = cardsList.item(i);// card
			if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
				Element fstElmnt = (Element) fstNode;
				String suit = fstElmnt.getAttribute("suit");// "DIAMONDS"
				String rank = fstElmnt.getAttribute("rank");// "ACE"

				if (suit.equals("DIAMONDS") && rank.equals("SIX")) {
					card = new Card(Rank.SIX, Suit.DIAMONDS);
					deck.addCard(card);
				}
				if (suit.equals("SPADES") && rank.equals("QUEEN")) {
					card = new Card(Rank.QUEEN, Suit.SPADES);
					deck.addCard(card);
				}
				if (suit.equals("DIAMONDS") && rank.equals("KING")) {
					card = new Card(Rank.KING, Suit.DIAMONDS);
					deck.addCard(card);
				}
				if (suit.equals("HEARTS") && rank.equals("KING"))//
				{
					card = new Card(Rank.KING, Suit.HEARTS);
					deck.addCard(card);
				}
				if (suit.equals("SPADES") && rank.equals("SIX")) {
					card = new Card(Rank.SIX, Suit.SPADES);
					deck.addCard(card);
				}
				if (suit.equals("HEARTS") && rank.equals("SIX")) {
					card = new Card(Rank.SIX, Suit.HEARTS);
					deck.addCard(card);
				}
				if (suit.equals("CLUBS") && rank.equals("SIX")) {
					card = new Card(Rank.SIX, Suit.CLUBS);
					deck.addCard(card);
				}
				if (suit.equals("CLUBS") && rank.equals("TEN")) {
					card = new Card(Rank.TEN, Suit.CLUBS);
					deck.addCard(card);
				}
				if (suit.equals("DIAMONDS") && rank.equals("SEVEN")) {
					card = new Card(Rank.SEVEN, Suit.DIAMONDS);
					deck.addCard(card);
				}
				if (suit.equals("SPADES") && rank.equals("TEN")) {
					card = new Card(Rank.TEN, Suit.SPADES);
					deck.addCard(card);
				}
				if (suit.equals("HEARTS") && rank.equals("JACK")) {
					card = new Card(Rank.JACK, Suit.HEARTS);
					deck.addCard(card);
				}
				if (suit.equals("CLUBS") && rank.equals("JACK")) {
					card = new Card(Rank.JACK, Suit.CLUBS);
					deck.addCard(card);
				}
				if (suit.equals("DIAMONDS") && rank.equals("ACE")) {
					card = new Card(Rank.ACE, Suit.DIAMONDS);
					deck.addCard(card);
				}
				if (suit.equals("SPADES") && rank.equals("EIGHT")) {
					card = new Card(Rank.EIGHT, Suit.SPADES);
					deck.addCard(card);
				}
				if (suit.equals("HEARTS") && rank.equals("NINE")) {
					card = new Card(Rank.NINE, Suit.HEARTS);
					deck.addCard(card);
				}
				if (suit.equals("DIAMONDS") && rank.equals("QUEEN")) {
					card = new Card(Rank.QUEEN, Suit.DIAMONDS);
					deck.addCard(card);
				}
				if (suit.equals("SPADES") && rank.equals("KING")) {
					card = new Card(Rank.KING, Suit.SPADES);
					deck.addCard(card);
				}
				if (suit.equals("DIAMONDS") && rank.equals("TEN")) {
					card = new Card(Rank.TEN, Suit.DIAMONDS);
					deck.addCard(card);
				}
				if (suit.equals("CLUBS") && rank.equals("EIGHT")) {
					card = new Card(Rank.EIGHT, Suit.CLUBS);
					deck.addCard(card);
				}
				if (suit.equals("HEARTS") && rank.equals("TEN")) {
					card = new Card(Rank.TEN, Suit.HEARTS);
					deck.addCard(card);
				}
				if (suit.equals("SPADES") && rank.equals("ACE")) {
					card = new Card(Rank.ACE, Suit.SPADES);
					deck.addCard(card);
				}
				if (suit.equals("HEARTS") && rank.equals("EIGHT")) {
					card = new Card(Rank.EIGHT, Suit.HEARTS);
					deck.addCard(card);
				}
				if (suit.equals("HEARTS") && rank.equals("SEVEN")) {

					card = new Card(Rank.SEVEN, Suit.HEARTS);
					deck.addCard(card);
				}
				if (suit.equals("HEARTS") && rank.equals("SEVEN")) {
					card = new Card(Rank.SEVEN, Suit.HEARTS);
					deck.addCard(card);
				}
				if (suit.equals("SPADES") && rank.equals("NINE")) {
					card = new Card(Rank.NINE, Suit.SPADES);
					deck.addCard(card);
				}
				if (suit.equals("SPADES") && rank.equals("SEVEN")) {
					card = new Card(Rank.SEVEN, Suit.SPADES);
					deck.addCard(card);
				}
				if (suit.equals("SPADES") && rank.equals("JACK")) {

					card = new Card(Rank.JACK, Suit.SPADES);
					deck.addCard(card);
				}
				if (suit.equals("HEARTS") && rank.equals("ACE")) {
					card = new Card(Rank.ACE, Suit.HEARTS);
					deck.addCard(card);
				}
				if (suit.equals("CLUBS") && rank.equals("QUEEN")) {
					card = new Card(Rank.QUEEN, Suit.CLUBS);
					deck.addCard(card);
				}
				if (suit.equals("CLUBS") && rank.equals("KING")) {
					card = new Card(Rank.KING, Suit.CLUBS);
					deck.addCard(card);
				}
				if (suit.equals("DIAMONDS") && rank.equals("JACK")) {
					card = new Card(Rank.JACK, Suit.DIAMONDS);
					deck.addCard(card);
				}
				if (suit.equals("CLUBS") && rank.equals("ACE")) {
					card = new Card(Rank.ACE, Suit.CLUBS);
					deck.addCard(card);
				}
				if (suit.equals("DIAMONDS") && rank.equals("EIGHT")) {
					card = new Card(Rank.EIGHT, Suit.DIAMONDS);
					deck.addCard(card);
				}
				if (suit.equals("HEARTS") && rank.equals("QUEEN")) {
					card = new Card(Rank.QUEEN, Suit.HEARTS);
					deck.addCard(card);
				}
				if (suit.equals("CLUBS") && rank.equals("SEVEN")) {
					card = new Card(Rank.SEVEN, Suit.CLUBS);
					deck.addCard(card);
				}
				if (suit.equals("DIAMONDS") && rank.equals("NINE")) {
					card = new Card(Rank.NINE, Suit.DIAMONDS);
					deck.addCard(card);
				}
				if (suit.equals("CLUBS") && rank.equals("NINE")) {
					card = new Card(Rank.NINE, Suit.CLUBS);
					deck.addCard(card);
				}

			}

		}

		print(deck, players);
	}

	public void print(DurakDeck deck, ArrayList<Player> p) {
		for (int i = 0; i < deck.size(); i++) {
			System.out.println(deck.getCardByLocation(i));
		}

		for (int i = 0; i < p.size(); i++) {
			System.out.println(p.get(i).getName() + " - " + p.get(i).getType());
		}
	}

	private void initAutoPlayers(int autoPlayers, Game currentGame) {
		for (int i = 0; autoPlayers > i; i++) {
			PlayerControl autoPlayer = new PlayerControlAutomatic(currentGame);
			autoPlayer.getPlayer().setType(playerType.COMPUTER);
			autoPlayer.getPlayer().setName(returnOnlyAuto().get(i).getName());
			currentGame.addPlayer(autoPlayer);
		}
	}

	private void initExpectedHumanPlayers(int humanPlayers, Game currentGame) {
		for (int i = 0; humanPlayers > i; i++) {
			currentGame.addExpectedHumanPlayersName(returnOnlyHuman().get(i).getName());
			
		}
	}
	
	public ArrayList<Player> returnOnlyHuman() {
		ArrayList<Player> onlyHuman = new ArrayList<Player>();
		for (int i = 0; i < players.size(); i++) {
			if (players.get(i).getType().compareTo(playerType.HUMAN) == 0)
				onlyHuman.add(players.get(i));
		}
		return onlyHuman;
	}

	public ArrayList<Player> returnOnlyAuto() {
		ArrayList<Player> onlyAuto = new ArrayList<Player>();
		for (int i = 0; i < players.size(); i++) {
			if (players.get(i).getType().compareTo(playerType.COMPUTER) == 0)
				onlyAuto.add(players.get(i));
		}
		return onlyAuto;
	}

	public DurakDeck returnDeck() {
		return deck;
	}
}